home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / C / GCC / V2-4-5 / GPPLIBSR00 / cc / outfloat < prev    next >
Text File  |  1993-08-04  |  6KB  |  191 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "ioprivate.h"
  19. #ifdef USE_DTOA
  20.  
  21. // Format floating-point number and print them.
  22. // Return number of chars printed, or EOF on error.
  23.  
  24. // sign_mode == '+' : print "-" or "+"
  25. // sign_mode == ' ' : print "-" or " "
  26. // sign_mode == '\0' : print "-' or ""
  27.  
  28. int __outfloat(double value, streambuf *sb, char type,
  29.            int width, int precision, ios::fmtflags flags,
  30.            char sign_mode, char fill)
  31. {
  32.     int count = 0;
  33. #define PUT(x) do {if (sb->sputc(x) < 0) goto error; count++;} while (0)
  34. #define PUTN(p, n) \
  35.   do {int _n=n; count+=_n; if (sb->sputn(p,_n) != _n) goto error;} while(0)
  36. #define PADN(fill, n) \
  37.   do {int _n = n; count+=_n; if (sb->padn(fill, _n) < 0) goto error;} while (0)
  38.     ios::fmtflags pad_kind = flags & (ios::left|ios::right|ios::internal);
  39.     int skip_zeroes = 0;
  40.     int show_dot = (flags & ios::showpoint) != 0;
  41.     int decpt;
  42.     int sign;
  43.     int mode;
  44. #define EBUF_SIZE 12
  45. #define EBUF_END &ebuf[EBUF_SIZE]
  46.     char ebuf[EBUF_SIZE];
  47.     char *end;
  48.     int exp = 0;
  49.     switch (type) {
  50.       case 'f':
  51.     mode = 3;
  52.     break;
  53.       case 'F':
  54.     exp = 'e';
  55.     mode = 0;
  56.     skip_zeroes = 1;
  57.     type = 'g';
  58.     break;
  59.       case 'e':
  60.     exp = 'e';
  61.     mode = 2;
  62.     precision++;  // Add one to include digit before decimal point.
  63.     break;
  64.       case 'E':
  65.     exp = 'E';
  66.     mode = 2;
  67.     precision++;  // Add one to include digit before decimal point.
  68.     break;
  69.       case 'g':
  70.       case 'G':
  71.     exp = type == 'g' ? 'e' : 'E';
  72.     if (precision == 0) precision = 1;
  73.     if (!(flags & ios::showpoint))
  74.         skip_zeroes = 1;
  75.     type = 'g';
  76.     mode = 2;
  77.     break;
  78.     }
  79.     /* Do the actual convension */
  80.     char *p = dtoa(value, mode, precision, &decpt, &sign, &end);
  81.     register int i;
  82.     int useful_digits = end-p;
  83.     char *exponent_start = EBUF_END;
  84.     // Check if we need to emit an exponent.
  85.     if (mode != 3 && decpt != 9999) {
  86.     i = decpt - 1;
  87.     if ((type != 'g' && type != 'F') || i < -4 || i >= precision) {
  88.         // Print the exponent into ebuf.
  89.         // We write ebuf in reverse order (right-to-left).
  90.         char sign;
  91.         if (i >= 0)
  92.         sign = '+';
  93.         else
  94.         sign = '-', i = -i;
  95.         /* Note: ANSI requires at least 2 exponent digits. */
  96.         do {
  97.         *--exponent_start = (i % 10) + '0';
  98.         i /= 10;
  99.         } while (i >= 10);
  100.         *--exponent_start = i + '0';
  101.         *--exponent_start = sign;
  102.         *--exponent_start = exp;
  103.     }
  104.     }
  105.     int exponent_size = EBUF_END - exponent_start;
  106.     if (mode == 1)
  107.     precision = 1;
  108.     /* If we print an exponent, always show just one digit before point. */
  109.     if (exponent_size)
  110.     decpt = 1;
  111.     if (decpt == 9999) { // Infinity or NaN
  112.     decpt = useful_digits;
  113.     precision = 0;
  114.     show_dot = 0;
  115.     }
  116.  
  117.    // dtoa truncates trailing zeroes.  Set the variable trailing_zeroes to
  118.    // the number of 0's we have to add (after the decimal point).
  119.    int trailing_zeroes = 0;
  120.    if (skip_zeroes)
  121.        trailing_zeroes = 0;
  122.    else if (type == 'f')
  123.        trailing_zeroes = useful_digits <= decpt ? precision
  124.        : precision-(useful_digits-decpt);
  125.    else if (exponent_size) // 'e' 'E' or 'g' format using exponential notation.
  126.        trailing_zeroes = precision - useful_digits;
  127.    else // 'g' format not using exponential notation.
  128.        trailing_zeroes = useful_digits <= decpt ? precision - decpt
  129.        : precision-useful_digits;
  130.     if (trailing_zeroes < 0) trailing_zeroes = 0;
  131.  
  132.     if (trailing_zeroes != 0 || useful_digits > decpt)
  133.     show_dot = 1;
  134.     int print_sign;
  135.     if (sign_mode == 0)
  136.     print_sign = sign ? '-' : 0;
  137.     else if (sign_mode == '+')
  138.     print_sign = sign ? '-' : '+';
  139.     else /* if (sign_mode == ' ') */
  140.     print_sign = sign ? '-' : ' ';
  141.     
  142.     // Calculate the width (before padding).
  143.     int unpadded_width =
  144.     (print_sign != 0) + trailing_zeroes + exponent_size + show_dot
  145.         + useful_digits
  146.         + (decpt > useful_digits ? decpt - useful_digits
  147.            : decpt > 0 ? 0 : 1 - decpt);
  148.  
  149.     int padding = width > unpadded_width ? width - unpadded_width : 0;
  150.     if (padding > 0
  151.     && pad_kind != (ios::fmtflags)ios::left
  152.     && pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust.
  153.     PADN(fill, padding);
  154.     if (print_sign)
  155.     PUT(print_sign);
  156.     if (pad_kind == (ios::fmtflags)ios::internal && padding > 0)
  157.     PADN(fill, padding);
  158.     if (decpt > 0) {
  159.     if (useful_digits >= decpt)
  160.         PUTN(p, decpt);
  161.     else {
  162.         PUTN(p, useful_digits);
  163.         PADN('0', decpt-useful_digits);
  164.     }
  165.     if (show_dot) {
  166.         PUT('.');
  167.         // Print digits after the decimal point.
  168.         if (useful_digits > decpt)
  169.         PUTN(p + decpt, useful_digits-decpt);
  170.     }
  171.     }
  172.     else {
  173.     PUT('0');
  174.     if (show_dot) {
  175.         PUT('.');
  176.         PADN('0', -decpt);
  177.         // Print digits after the decimal point.
  178.         PUTN(p, useful_digits);
  179.     }
  180.     }
  181.     PADN('0', trailing_zeroes);
  182.     if (exponent_size)
  183.     PUTN(exponent_start, exponent_size);
  184.     if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment
  185.     PADN(fill, padding);
  186.     return count;
  187.   error:
  188.     return EOF;
  189. }
  190. #endif
  191.